// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2004-11-18

#include "stdafx.h"
#include "base_buffer.h"
#include <common/base/mempool.h>

namespace JoyServer
{

namespace JoyBufferMem
{

//#define JOY_BUFFER_BLOCK_SIZE 64
//#define JOY_BUFFER_BLOCK_MASK ~0x3F

#define JOY_BUFFER_BLOCK_SIZE 4096
#define JOY_BUFFER_BLOCK_MASK ~0xFFF

#pragma warning(disable : 4074)
#pragma warning(disable : 4073)
#pragma init_seg(lib)
static CJoyMemPool s_poolObj(JOY_BUFFER_BLOCK_SIZE, 16, 16);
static CJoyCriticalSection  s_poolLock;

inline static int Round(int nSize)
{
    return (nSize+JOY_BUFFER_BLOCK_SIZE-1)&(~(JOY_BUFFER_BLOCK_SIZE-1));
}

void* Alloc(size_t s)
{
    CJoyAutoCS gate(s_poolLock);
    return s_poolObj.Alloc(s);
}

void Free(void* p)
{
    CJoyAutoCS gate(s_poolLock);
    s_poolObj.Free(p);
}

} // namespace JoyBufferMem

// class CJoyBuffer

//##ModelId=44CEFAD1017A
CJoyBuffer::CJoyBuffer():
    m_buf(NULL), m_size(0), m_allocSize(0)
{
}

//##ModelId=44CEFAD1017B
CJoyBuffer::CJoyBuffer(int nSize)
{
    if(nSize > 0)
    {
        m_allocSize = JoyBufferMem::Round(nSize);
        m_buf  = JoyBufferMem::Alloc(m_allocSize);
        m_size = nSize;
    }
    else
    {
        m_allocSize = 0;
        m_size = 0;
        m_buf  = NULL;
    }
}

//##ModelId=44CEFAD10186
CJoyBuffer::CJoyBuffer(const void* buf, int nSize)
{
    if(nSize > 0)
    {
        m_allocSize = JoyBufferMem::Round(nSize);
        m_buf  = JoyBufferMem::Alloc(m_allocSize);
        m_size = nSize;
        memcpy(m_buf, buf, nSize);
    }
    else
    {
        m_allocSize = 0;
        m_size = 0;
        m_buf  = NULL;
    }
}

//##ModelId=44CEFAD10189
CJoyBuffer::~CJoyBuffer()
{
    if(m_buf != NULL)
    {
        JoyBufferMem::Free(m_buf);
    }
}

//##ModelId=44CEFAD10196
void CJoyBuffer::SetSize(int nSize)
{
    if(nSize <= m_allocSize)
    {
        m_size = nSize;
        return;
    }
    m_allocSize = JoyBufferMem::Round(nSize);
    void* buf = m_buf;
    m_buf = JoyBufferMem::Alloc(m_allocSize);
    if(buf != NULL)
    {
        if(m_size > 0)
        {
            memcpy(m_buf, buf, m_size);
        }
        JoyBufferMem::Free(buf);
    }
    m_size = nSize;
}

//##ModelId=44CEFAD1019E
void CJoyBuffer::Append(const void* buf, int len)
{
    if(len == 0)
    {
        return;
    }
    int s = m_size;
    SetSize(s+len);
    memcpy((char*)m_buf+s, buf, len);
}

//##ModelId=44CEFAD10198
void CJoyBuffer::RemoveAll()
{
    if(m_buf != NULL)
    {
        JoyBufferMem::Free(m_buf);
        m_allocSize = 0;
        m_size = 0;
        m_buf  = NULL;
    }
}

//##ModelId=44CEFAD1019C
void CJoyBuffer::Remove(void* stop)
{
    Remove(m_buf, stop);
}

//##ModelId=44CEFAD10199
void CJoyBuffer::Remove(void* start, void* stop)
{
    ASSERT(start <= stop);
    if(start == stop)
    {
        return;
    }
    void* end = (char*)m_buf+m_size;
    ASSERT(start >= m_buf);
    ASSERT(stop <= end);

    int s = (int)(INT_PTR)((char*)end-(char*)stop);
    memmove(start, stop, s);
    m_size -= (int)(INT_PTR)((char*)stop-(char*)start);
}

//##ModelId=44CEFAD101A5
void CJoyBuffer::BatchAppend(const void* const * bufs, int* lens, int count)
{
    int total = 0;
    for(int i = 0; i < count; ++ i)
    {
        total += lens[i];
    }
    int origSize = m_size;
    SetSize(origSize+total);

    BYTE* dst = (BYTE*)m_buf+origSize;

    for(int i = 0; i < count; ++ i)
    {
        memcpy(dst, bufs[i], lens[i]);
        dst += lens[i];
    };
}

//##ModelId=44CEFAD101A9
void CJoyBuffer::Replace(int relPos, int relLen, const void* buf, int len)
{
    int newSize = m_size + len - relLen;
    if(newSize > m_allocSize)
    {
        m_allocSize = JoyBufferMem::Round(newSize);
        void* origBuf = m_buf;
        m_buf = JoyBufferMem::Alloc(m_allocSize);
        if(origBuf != NULL)
        {
            BYTE* dst = (BYTE*)m_buf;
            BYTE* src = (BYTE*)origBuf;
            memcpy(dst, src, relPos);
            dst += relPos;
            src += relPos+relLen;
            memcpy(dst, buf, len);
            dst += len;
            memcpy(dst, src, m_size-relPos-relLen);
            JoyBufferMem::Free(origBuf);
        }
    }
    else
    {
        BYTE* dst = (BYTE*)m_buf+relPos+len;
        BYTE* src = (BYTE*)m_buf+relPos+relLen;
        memmove(dst, src, m_size-relPos-relLen);
        dst = (BYTE*)m_buf+relPos;
        memcpy(dst, buf, len);
    }
    m_size = newSize;
}

} // namespace JoyServer
